package cn.cool.infrastructure.limiter;

import cn.cool.infrastructure.dcc.DCCService;
import cn.cool.types.exception.AppException;
import cn.hutool.core.util.StrUtil;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowItem;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service("groupBuyLockOrderRateLimiter")
public class GroupBuyLockOrderRateLimiter {
    @Resource
    private DCCService dccService;

    private static final String GROUP_BUY_LOCK_ORDER_RESOURCE = "group_buy_lock_order_limit";
    private static final String GROUP_BUY_ACTIVITY_PREFIX = "activity-";
    private static final String GROUP_BUY_GOODS_PREFIX = "goods-";

    // 最后一次有效配置
    private Map<String, Integer> lastConfig = new ConcurrentHashMap<>();

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @PostConstruct
    private void init() {
        loadRules();
    }

    private synchronized void loadRules() {
        try {
            ParamFlowRule rule = new ParamFlowRule(GROUP_BUY_LOCK_ORDER_RESOURCE)
                    .setParamIdx(0)
                    .setGrade(RuleConstant.FLOW_GRADE_QPS)
                    .setCount(dccService.getDefaultLockOrderLimit());

            Map<String, Integer> limitConfig = getLimitConfig();
            List<ParamFlowItem> paramFlowItems = new ArrayList<>(limitConfig.size());
            limitConfig.forEach((limitParam, limitCount) -> {
                paramFlowItems.add(
                        new ParamFlowItem().setObject(limitParam)
                                .setClassType(String.class.getName())
                                .setCount(limitCount)
                );
            });

            rule.setParamFlowItemList(paramFlowItems);

            ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
        } catch (Exception e) {
            throw new AppException("加载拼团活动限流异常", e);
        }
    }

    private Map<String, Integer> getLimitConfig() {
        // 1. 从 Redis读取json配置
        String configJson = dccService.getHotParamFlowRules();
        if (StrUtil.isBlank(configJson)) {
            log.warn("限流配置位空，使用默认值");
            return Collections.emptyMap();
        }

        // 2. 解析 json
        Map<String, Map<String, Integer>> configMap;
        try {
            configMap = objectMapper.readValue(
                    configJson,
                    new TypeReference<Map<String, Map<String, Integer>>>() {}
            );
        } catch (JsonProcessingException e) {
            log.error("限流配置解析失败", e);
            return lastConfig;
        }

        // 3. 转换成HashMap
        Map<String, Integer> result = new HashMap<>();
        configMap.forEach((activityId, goodsMap) -> {
            goodsMap.forEach((goodsId, limit) -> {
                result.put(activityId + ":" + goodsId, limit);
            });
        });

        lastConfig = result;
        return result;
    }

    public void checkLimit(String activityId, String goodsId) {
        final String parameter = GROUP_BUY_ACTIVITY_PREFIX + activityId + ":" + GROUP_BUY_GOODS_PREFIX + goodsId;
        try (Entry entry = SphU.entry(GROUP_BUY_LOCK_ORDER_RESOURCE, EntryType.IN, 1, parameter)) {
            // todo 通过限流检查
        } catch (BlockException e) {
            throw new AppException("活动太火爆，请稍后再试", e);
        }
    }

}









































































